package main

import (
	"context"
	"fmt"
	"strconv"
	"sync"
	"time"
)

var (
	xc int = 0

	chanSign = make(chan bool)
)

func main() {
	//createChan()
	//testForChan()
	//outChan2()
	//TestReturnChan()
	//testChan()
	defineTest()
	//simpleDefine()
}

type Lock struct {
	unlockChan chan struct{}
	//unlockChan chan int
	localLock *sync.Mutex
	isLocked  bool
	cancel    context.CancelFunc
	timeOut   time.Duration
}

func (t *Lock) unlockLocalLock() {
	if t.unlockChan != nil && t.isLocked {
		select {
		case _, ok := <-t.unlockChan:
			if ok {
				close(t.unlockChan)
			}
		default:
			close(t.unlockChan)
		}
	}
}

func testChan() {
	lock := Lock{localLock: &sync.Mutex{}, timeOut: time.Second * 10}
	lock.unlockChan = make(chan struct{}, 1)
	lock.localLock.Lock()
	go func() {
		x := <-lock.unlockChan
		fmt.Println("解锁了 :", x)

	}()
	lock.isLocked = true
	fmt.Println("执行程序")
	for {
		time.Sleep(time.Second * 2)
		ctx, cancel := context.WithTimeout(context.Background(), lock.timeOut)
		lock.cancel = cancel
		go func() {
			<-ctx.Done()
			fmt.Println("超时了")
			if ctx.Err() == context.DeadlineExceeded {
				fmt.Println(ctx.Err())
				lock.unlockLocalLock()
			}
		}()
		/*		if lock.cancel != nil {
				fmt.Println("~!")
				//lock.cancel()
			}*/
		lock.unlockLocalLock()
	}
}

func TestReturnChan() {
	c1 := getChan1()
	fmt.Println(<-c1)
	c2 := getChan2()
	//fmt.Println(<-c2)  send-only
	c2 <- 1
	c3 := getChan3()
	fmt.Println(<-c3)
	for {

	}
}

func getChan1() <-chan interface{} {
	c := make(chan interface{}, 1)
	c <- 1
	return c
}

func getChan2() chan<- int {
	c := make(chan int, 1)
	go func() {
		for {
			select {
			case v := <-c:
				fmt.Println("C2 Value :", v)
			}
		}
	}()
	return c
}

func getChan3() chan int {
	c := make(chan int, 1)
	c <- 1
	return c
}

func testForChan() {
	//chanFor := make(chan interface{}, 2)
	chanC := make(chan interface{}, 1)
	//chanFor := make(chan time.Time)
	chanFor := time.Tick(time.Second * 1)
	time.Tick(time.Second * 2)
	i := 0
	for _ = range chanFor {
		i++
		select {
		case x := <-chanC:
			fmt.Println(x)
		default:
			type testT struct {
				name string
				age  int
				test chan int
			}
			chanC <- testT{name: "test", age: i}
		}
		time.Sleep(time.Second * 2)
	}
}

func TimeTicketChan() {
	c := time.Tick(time.Second * 5)
	for _ = range c {
		select {
		case <-chanSign:
			return
		default:
			go func() {
				fmt.Println("123")
				go func() {
					chanSign <- false
				}()
			}()
		}
	}
}

func createChan() {
	chs := make([]chan int, 10)
	lock := &sync.Mutex{}
	for i := 0; i < 10; i++ {
		chs[i] = make(chan int)
		go func(x chan int, mutex *sync.Mutex) {
			mutex.Lock()
			x <- xc
			//xc ++
			mutex.Unlock()
			fmt.Println("exit", xc)
		}(chs[i], lock)
	}
	for i := 0; i < 10; i++ {
		fmt.Println(<-chs[i])
	}
	time.Sleep(time.Second * 5)
}

func testClostMain() {
	chanClose := make(chan int)
	chandata := make(chan string, 1024)
	go testClose(chandata, chanClose)
	go send(chandata, chanClose)
	select {}
}

func testClose(data chan string, close chan int) {
	for {
		select {
		case x := <-data:
			fmt.Println("data :", x)
		case <-close:
			fmt.Println("occur :")
			return
		}
	}
}

func send(data chan string, closec chan int) {
	start := time.Now()
	for {
		if time.Since(start) > time.Second*5 {
			close(closec)
		}
		data <- "1111"
		time.Sleep(time.Second * 1)
	}
}

var maxChan = make(chan int, 60)
var count = 0
var start = time.Now()

func test1() {
	c := make(chan int, 1024)
	go timeOut(c)

	go func() {
		for {
			handle()
		}
	}()
	select {}
}

func timeOut(x <-chan int) {
	for m := range x {
		time.Sleep(time.Second)
		fmt.Println(m)
	}
}
func handle() {
	maxChan <- 1
	count++
	fmt.Println("enter ", count)
}

func directionMethod() {
	c := make(chan int)
	o := make(chan bool)
	go func() {
		for {
			go ttt(c)
			select {
			case i := <-c:
				fmt.Println(i)
			case <-time.After(time.Duration(3) * time.Second):
				fmt.Println("timeout")
				o <- true
				break
			}
		}
	}()
	<-o
}

func ttt(c chan int) {
	time.Sleep(time.Second * 4)
	c <- 7
}

func outChan1() {
	x := returnTest()
	go func() {
		for v := range x {
			fmt.Println(v)
		}
	}()

	select {}
}

func outChan2() {
	x := returnTest()
	for {
		select {
		case res := <-x:
			go func() {
				fmt.Println(res)
			}()
		case <-time.After(time.Second * 10):
			fmt.Println("time out")
			return
		}
	}
}

func returnTest() <-chan string {
	ch1 := make(chan string)
	go intoChan(ch1)
	return ch1
}

func intoChan(x1 chan string) {
	for i := 0; i < 10; i++ {
		x1 <- strconv.Itoa(i)
	}
	time.Sleep(time.Second * 2)
	intoChan(x1)
}

func defineTest() {
	const t = 5
	var chans [5]<-chan int
	for i := range chans {
		go func(x int) {
			c := func() <-chan int {
				ch := make(chan int, 1)
				defer close(ch)
				ch <- x
				return ch
			}()
			fmt.Println(c)
			chans[x] = c
		}(i)
	}
	time.Sleep(5 * time.Second)
	for _, v := range chans {
		func(c <-chan int) {
			fmt.Println(<-c)
		}(v)
	}
}

func simpleDefine() {
	var ch <-chan int
	fn := func() <-chan int {
		ch := make(chan int, 10)
		defer close(ch)
		ch <- 12
		return ch
	}
	go func() {
		var i = 1
		for i < 3 {
			ch = fn()
			i++
		}
	}()
	time.Sleep(500)
	for {
		select {
		case x := <-ch:
			fmt.Println(x)
		case <-time.After(time.Second * 5):
			fmt.Println(<-ch)
			fmt.Println("超时")
		}
		time.Sleep(1 * time.Second)
	}
}
